import { defineStore } from 'pinia';
import { parse } from 'qs';
import { filter, forEach, loadToken, map, nextId, openSse, openWebSocket, request, signin } from '@/soar';
import * as accountApi from '@/api/account';
import { changeTenant } from '@/api/account';
import * as loginApi from '@/api/login';
import { addRoute, getLocalRoutes, refreshRoute } from '@/router';
import { COMPONENTS } from '@/constants';

const Layout = () => import('@/layouts/index.vue');

// 获取渲染组件
function getComponent(x) {
  let { component } = x;
  if (!component) {
    return null;
  }
  // 添加 .vue 尾缀
  if (component.lastIndexOf('.') === -1) {
    component += '.vue';
  }
  // 查找组件
  return COMPONENTS[component];
}

// 转换为路由
function toRoutes(menus: any[]) {
  // 过滤按钮
  menus = filter(menus, (x) => x.type !== 0);
  menus = menus.flatMap((x) => (x.type === 3 ? x.children || [] : [x]));
  // 处理重定向
  forEach(menus, (x) => {
    if (x.type === 1 && !x.redirect && x.children?.length) {
      x.redirect = x.children[0].path;
    }
  });
  // 转为路由结构
  menus = map(menus, (route) => {
    return {
      name: route.code,
      path: route.path,
      redirect: route.redirect,
      component: getComponent(route),
      meta: {
        title: route.title,
        icon: route.icon,
        hidden: route.status === 1,
        hideChildren: route.hideChildren,
        isAlive: route.keepalive,
        shared: route.shared,
        permit: route.code,
        sort: route.sort,
      },
    };
  });
  for (let i = 0; i < menus.length; i++) {
    const menu = menus[i];
    if (!menu.component || menu.children?.length > 0) {
      continue;
    }
    menus[i] = {
      path: '',
      name: `$${nextId()}`,
      redirect: menu.path,
      component: Layout,
      meta: { hiddenSelf: true },
      children: [menu],
      sort: menu.sort,
    };
  }
  return menus;
}

function ssoLogin() {
  if (import.meta.env.VITE_SSO_ENABLED_CLIENT !== 'true') {
    return Promise.reject();
  }
  const query = parse(window.location.search.substring(1));
  const ticket = query.ticket as string;
  if (!ticket) {
    let path = import.meta.env.VITE_SSO_SERVER_URL;
    // eslint-disable-next-line no-restricted-globals
    path = `${path}${path.includes('?') ? '&' : '?'}redirect=${decodeURIComponent(location.href)}&serverId=`;
    window.location.href = path;
    return Promise.reject();
  }
  return request
    .post('/system/sso/client/validation', {
      title: '单点登录',
      successMsg: '欢迎回来',
      data: { ticket, serverId: query.serverId },
    })
    .then((res) => {
      signin(res);
      return res;
    });
}

interface User {
  id?: string;
  username?: string;
  nickname?: string;
  avatar?: string;
  currentTenantId?: number;
  userType?: number;
  status?: number;
}

interface AccountStore {
  /**
   * 是否是超级管理员
   */
  superAdministrator: boolean;
  /**
   * 用户信息
   */
  user: User;
  /**
   * 角色
   */
  roles: string[];
  /**
   * 权限数据
   */
  permits: string[];
  /**
   * 路由
   */
  routes: any[];
  /**
   * 是否显示登陆弹窗
   */
  loginModalVisible: boolean;
}

export const useAccountStore = defineStore<string, AccountStore>('account', {
  state: () => ({
    superAdministrator: false,
    user: {},
    roles: [],
    permits: [],
    routes: [],
    loginModalVisible: false,
  }),
  actions: {
    /**
     * 登录
     * @param userInfo
     */
    login(userInfo: Record<string, unknown>) {
      return loginApi.account(userInfo).then((res) => {
        this.loginModalVisible = false;
        this.getUserInfo();
        return res;
      });
    },
    /**
     * 退出登录
     */
    logout() {
      // 调用后端退出
      accountApi.logout();
      // 刷新路由信息
      refreshRoute();
      // 清除用户信息
      this.loginModalVisible = false;
      this.superAdministrator = false;
      this.user = {};
      this.roles = [];
      this.permits = [];
      this.routes = [];
    },
    /**
     * 获取用户信息
     */
    getUserInfo() {
      return accountApi.getUserInfo().then((res) => {
        // 开启websocket
        openWebSocket();
        openSse();
        // 处理用户信息
        this.loginModalVisible = false;
        this.superAdministrator = res.superAdministrator ?? false;
        this.user = res.user ?? {};
        this.roles = res.roles ?? [];
        const permits = [];
        forEach(res.menus, (x) => {
          if (x.type === 0) {
            permits.push(x.code);
          }
        });
        this.permits = permits; // res.permits ?? [];

        // 处理路由
        const routes = toRoutes(res.menus ?? []);
        const localRoutes = getLocalRoutes();
        this.routes = routes.concat(localRoutes);
        refreshRoute(this.routes);
        // 动态添加404匹配
        addRoute([
          {
            path: '/:w+',
            name: '404Page',
            redirect: '/result/404',
          },
        ]);
        return res;
      });
    },
    /**
     * 更新用户信息
     * @param data
     */
    updateInfo(data: { nickname?: string; avatar?: string }) {
      return accountApi.updateInfo(data).then((res: any) => {
        this.getUserInfo();
        return res;
      });
    },
    /**
     * 是否登录
     */
    isLogin() {
      return new Promise((resolve, reject) => {
        // 判断token有效性
        loadToken()
          .then(() => {
            // 判断是否有id（判断是否获取了用户信息）
            if (this.user?.id) {
              // @ts-ignore 存在id直接通过
              resolve();
            } else {
              // 重新查询用户信息
              this.getUserInfo().then(resolve).catch(reject);
            }
          })
          .catch((e) => {
            ssoLogin()
              .then(() => {
                this.loginModalVisible = false;
                // 重新查询用户信息
                this.getUserInfo().then(resolve).catch(reject);
              })
              .catch(() => reject(e));
          });
      });
    },
    // @ts-ignore
    updateLoginModalVisible(b?: boolean) {
      if (typeof b === 'boolean') {
        this.loginModalVisible = b;
      } else {
        this.loginModalVisible = !this.loginModalVisible;
      }
    },
    changeTenant(tenantId: string) {
      return changeTenant(tenantId).then((res) => {
        signin(res);
        this.user.currentTenantId = tenantId;
        return res;
      });
    },
  },
});
